package src.server;

import src.config.SysConfig;
import src.mysql.MysqlHelper;
import src.server.SocketHelper;

import java.io.IOException;
import java.net.Socket;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.Objects;
import java.util.zip.DataFormatException;

/**
 * @author CsCN
 * 此类可能可以合并到LoginServer类中, 便于减少sql预编译次数, 提高性能, 但是可能会导致线程竞争问题
 */
public class LoginThread extends Thread {
    private final String usersTableName = SysConfig.MYSQL_USERS_TABLE_NAME;
    private final Socket socket;
    private String activity;
    private String username;
    private String password;
    private final MysqlHelper mysqlHelper;

    public LoginThread(Socket socket) {
        this.socket = socket;
        mysqlHelper = new MysqlHelper();
    }

    @Override
    public void run() {
        System.out.println("login thread started");
        recvMessage();
        String message = null;
        switch (activity) {
            // 登录
            case "login":
                if (checkPassword()) {
                    message = "OK";
                } else {
                    message = "SB";
                }
                break;
            // 注册
            case "create":
                if (createAccount()) {
                    message = "OK";
                } else {
                    message = "SB";
                }
                break;
            default:
                message = "???";
                break;
        }
        SocketHelper.sendString(socket, message);
        // 线程结束, 关闭Socket
        try {
            socket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 通过Socket获得发送来的消息, 并进行解析
     */
    private void recvMessage() {
        try {
            // 接收字符串
            String rec = SocketHelper.recvString(socket);
            // 检查是否符合格式要求
            String[] splited = rec.split("\n");
            if (splited.length != 3) {
                throw new DataFormatException("received data is not in format: (activity username password)");
            }
            // 设置变量
            activity = splited[0];
            username = splited[1];
            password = splited[2];
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 在数据库中检查密码是否正确
     *
     * @return 密码是否正确
     */
    private boolean checkPassword() {
        createTable();
        return Objects.equals(password, getPassword());
    }

    /**
     * 添加表格
     */
    private void createTable() {
        String sql = "create table if not exists `" + usersTableName + "` ("
                + "`id` int unsigned auto_increment,"
                + "`username` varchar(50) not null,"
                + "`password` varchar(32) not null,"
                + "primary key (`id`));";
        mysqlHelper.executeRaw(sql);
    }

    /**
     * 根据用户名, 查找到密码
     * @return 用户名对应的密码, 如果没有返回null
     */
    private String getPassword() {
        try {
            String sql = "select * from `" + usersTableName + "` where username=?;";
            PreparedStatement statement = mysqlHelper.getPreparedStatement(sql);
            statement.setString(1, username);
            System.out.println(statement);
            ResultSet resultSet = statement.executeQuery();
            if(!resultSet.next()){
                return null;
            } else {
                return resultSet.getString("password");
            }
        }catch (Exception e){
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 将新的账户添加到数据库中
     */
    private boolean createAccount() {
        if (getPassword() != null) {
            return false;
        }
        try {
            // 预编译sql语句, 防止sql注入错误
            String sql = "insert into `" + usersTableName + "` (username, password) values (?, ?);";
            PreparedStatement statement = mysqlHelper.getPreparedStatement(sql);
            statement.setString(1, username);
            statement.setString(2, password);
            System.out.println(statement);
            statement.executeUpdate();
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }
}
